﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

using Microsoft.SharePoint;

using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.ExceptionManagement;

using DocumentFieldNames = Kiiro.Common.Utility.Constants.DocumentFieldNames;
using System.Web.UI.WebControls;

namespace Kiiro.DataAccess
{
    public class DocumentDA
    {
        #region Singleton

        private DocumentDA ( )
        {
        }

        private static DocumentDA instance = null;
        private static readonly object threadLock = new object ( );

        public static DocumentDA Instance
        {
            get
            {
                lock ( threadLock )
                {
                    if ( instance == null )
                    {
                        instance = new DocumentDA ( );
                    }
                }
                return instance;
            }
        }

        #endregion

        public Document GetDocumentById ( int id, Guid siteCollectionId, string serverRelativeUrl )
        {
            Document document = null;

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    SPList docsList = web.Lists [ Constants.SPListNames.Documents ];

                    SPListItem docListItem = docsList.GetItemById ( id );

                    if ( docListItem.Folder != null )
                        document = SPDataHelpers.MakeDocumentFromFolderItem ( docListItem );
                    else if ( docListItem.File != null )
                        document = SPDataHelpers.MakeDocumentFromFileItem ( docListItem );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return document;
        }


        public Document GetDocumentByUrl ( string documentUrl, int documentId, Guid siteCollectionId, string serverRelativeUrl )
        {
            Document document = null;

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    object file = null;
                    try
                    {
                        file = web.GetFileOrFolderObject ( documentUrl );
                    }
                    catch ( Exception ex )
                    {
                        ExceptionManager.HandleException ( ex, false );
                    }

                    if ( file != null )
                    {
                        if ( file is SPFile && ( ( SPFile ) file ).Exists )
                        {
                            document = SPDataHelpers.MakeDocumentFromFileItem ( ( ( SPFile ) file ).Item );
                            document.ServerRelativeUrl = ( ( SPFile ) file ).ServerRelativeUrl;
                            document.SiteCollectionId = siteCollectionId;
                        }
                        else if ( file is SPFolder && ( ( SPFolder ) file ).Exists )
                        {
                            document = SPDataHelpers.MakeDocumentFromFolderItem ( ( ( SPFolder ) file ).Item );
                            document.ServerRelativeUrl = ( ( SPFolder ) file ).ServerRelativeUrl;
                            document.SiteCollectionId = siteCollectionId;
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return document;
        }

        public List<Document> GetAllDocuments ( Guid siteCollectionId, string serverRelativeUrl )
        {
            List<Document> documents = new List<Document> ( );

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    SPList list = web.Lists [ Constants.SPListNames.Documents ];
                    SPView view = list.DefaultView;
                    SPQuery query = new SPQuery ( view );
                    query.ViewAttributes = "Scope=\"Recursive\"";
                    SPListItemCollection items = list.GetItems ( query );

                    foreach ( SPListItem item in items )
                    {
                        if ( item.File != null )
                        {
                            documents.Add ( SPDataHelpers.MakeDocumentFromFileItem ( item.File.Item ) );
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return documents;
        }

        public List<Document> GetDocumentsByIds ( List<int> documentIds, Guid siteCollectionId, string serverRelativeUrl )
        {
            List<Document> documents = new List<Document> ( );
            SPList list = null;

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    list = web.Lists [ Constants.SPListNames.Documents ];

                    if ( list != null )
                    {
                        SPQuery query = new SPQuery ( );
                        query.ViewAttributes = "Scope=\"Recursive\"";

                        bool first = true;
                        foreach ( int documentId in documentIds )
                        {
                            if ( !first ) query.Query = "<Or>" + query.Query;
                            query.Query += "<Eq><FieldRef Name='ID'/><Value Type='Integer'>" + documentId + "</Value></Eq>";
                            if ( !first ) query.Query += "</Or>";

                            first = false;
                        }

                        if ( !string.IsNullOrEmpty ( query.Query ) )
                            query.Query = "<Where>" + query.Query + "</Where>";

                        SPListItemCollection items = list.GetItems ( query );

                        foreach ( SPListItem item in items )
                        {
                            if ( item.File != null )
                            {
                                try
                                {
                                    Document document = SPDataHelpers.MakeDocumentFromFileItem ( item.File.Item );
                                    document.ServerRelativeUrl = item.File.ServerRelativeUrl;
                                    document.SiteCollectionId = siteCollectionId;
                                    documents.Add ( document );
                                }
                                catch ( Exception ex )
                                {
                                    ExceptionManager.HandleException ( ex, false );
                                }
                            }
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return documents;
        }

        public List<Document> GetDocumentsByUrls ( List<string> documentUrls, Guid siteCollectionId, string serverRelativeUrl )
        {
            SPWeb web = null;
            List<Document> documents = new List<Document> ( );

            try
            {

                web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl );

                foreach ( string documentUrl in documentUrls )
                {
                    try
                    {
                        string docUrl = documentUrl;
                        if ( SPHelpers.IsProject ( siteCollectionId, serverRelativeUrl )
                            && Microsoft.SharePoint.Utilities.SPUrlUtility.IsUrlRelative ( documentUrl ) )
                        {
                            docUrl = SPHelpers.GetAbsoluteUrl ( siteCollectionId, serverRelativeUrl ) + "/" + documentUrl;
                        }
                        SPFile file = web.GetFile ( documentUrl );
                        if ( file.Exists )
                        {
                            object obj = web.GetFileOrFolderObject ( docUrl );
                            file = ( SPFile ) obj;
                            if ( file != null && file.Exists )
                            {
                                Document document = SPDataHelpers.MakeDocumentFromFileItem ( file.Item );
                                document.ServerRelativeUrl = file.ServerRelativeUrl;
                                document.SiteCollectionId = siteCollectionId;
                                documents.Add ( document );
                            }
                        }
                    }
                    catch ( Exception ex )
                    {
                        ExceptionManager.HandleException ( ex, false );
                    }
                }
            }
            finally
            {
                if ( web != null )
                {
                    web.Dispose ( );
                }
            }

            return documents;
        }





        public List<Document> GetDocumentsByFolder ( Guid siteCollectionId, string serverRelativeUrl, string folderWebRelativeUrl )
        {
            List<Document> folders = new List<Document> ( );
            List<Document> documents = new List<Document> ( );

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    SPFolder rootFolder = web.GetFolder ( folderWebRelativeUrl );

                    foreach ( SPFolder subFolder in rootFolder.SubFolders )
                    {
                        if ( subFolder.Item != null )
                        {
                            Document folder = SPDataHelpers.MakeDocumentFromFolderItem ( subFolder.Item );
                            folder.Contains = subFolder.SubFolders.Count + subFolder.Files.Count;
                            folders.Add ( folder );
                        }
                    }

                    foreach ( SPFile file in rootFolder.Files )
                    {
                        if ( file.Item != null )
                        {
                            Document doc = SPDataHelpers.MakeDocumentFromFileItem ( file.Item );
                            doc.CreatedBy = UserDA.Instance.GetUserByLogin ( doc.CreatedBy.Login, siteCollectionId, serverRelativeUrl );
                            doc.ModifiedBy = UserDA.Instance.GetUserByLogin ( doc.ModifiedBy.Login, siteCollectionId, serverRelativeUrl );
                            documents.Add ( doc );
                        }
                    }

                    documents.InsertRange ( 0, folders );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return documents;
        }

        [Obsolete] // using on DocumentHistory.aspx as other method returns null
        public List<Document> GetDocumentVersions ( int documentId, Guid siteCollectionId, string serverRelativeUrl )
        {
            List<Document> documentVersions = new List<Document> ( );

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    SPList documentList = web.Lists [ Constants.SPListNames.Documents ];

                    SPListItem documentItem = documentList.GetItemById ( documentId );

                    int currVersion = documentItem.Versions.Count;
                    foreach ( SPListItemVersion documentVersion in documentItem.Versions )
                    {

                        Document doc = new Document ( );
                        doc.Title = documentVersion.ListItem.File.Name;
                        doc.Version = documentVersion.VersionId;
                        doc.VersionLabel = documentVersion.VersionLabel;
                        doc.Url = documentVersion.Url;
                        doc.ModifiedBy = UserDA.Instance.GetUserByLogin ( documentVersion.CreatedBy.User.LoginName, siteCollectionId, serverRelativeUrl );
                        doc.ModifiedDate = documentVersion.Created;
                        doc.IsProjectPlan = SPDataHelpers.GetBooleanValue ( documentItem, DocumentFieldNames.IsProjectPlan );

                        if ( currVersion < documentItem.Versions.Count - 1 )
                            doc.FileLength = documentItem.File.Versions [ currVersion ].Size;
                        else
                            doc.FileLength = documentVersion.ListItem.File.Length;
                        documentVersions.Add ( doc );
                        currVersion--;
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return documentVersions;
        }

        public List<Document> GetDocumentVersions ( string documentUrl, int documentId, Guid siteCollectionId, string serverRelativeUrl )
        {
            List<Document> documentVersions = null;

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    StringBuilder queryText = new StringBuilder ( );
                    queryText.Append ( "<Where>" );
                    queryText.Append ( "  <Or>" );
                    queryText.Append ( "      <Eq><FieldRef Name='ID'/><Value Type='Integer'>" + documentId + "</Value></Eq>" );
                    queryText.Append ( "      <Eq><FieldRef Name='FileRef'/><Value Type='Lookup'>" + documentId + ";#" + serverRelativeUrl.Substring ( 1 ) + "/" + documentUrl + "</Value></Eq>" );
                    queryText.Append ( "  </Or>" );
                    queryText.Append ( "</Where>" );

                    SPQuery query = new SPQuery ( );
                    query.Query = queryText.ToString ( );

                    SPList documentList = web.Lists [ Constants.SPListNames.Documents ];

                    SPListItemCollection documents = documentList.GetItems ( query );

                    if ( documents.Count > 0 )
                    {
                        documentVersions = new List<Document> ( );
                        SPListItem documentItem = documentList.GetItemById ( documentId );

                        int currVersion = documentItem.Versions.Count;
                        foreach ( SPListItemVersion documentVersion in documentItem.Versions )
                        {
                            Document doc = new Document ( );
                            doc.Title = documentVersion.ListItem.File.Name;
                            doc.Version = documentVersion.VersionId;
                            doc.VersionLabel = documentVersion.VersionLabel;
                            doc.Url = documentVersion.Url;
                            doc.ModifiedBy = UserDA.Instance.GetUserByLogin ( documentVersion.CreatedBy.User.LoginName, siteCollectionId, serverRelativeUrl );
                            doc.ModifiedDate = documentVersion.Created;
                            doc.IsProjectPlan = SPDataHelpers.GetBooleanValue ( documentItem, DocumentFieldNames.IsProjectPlan );

                            if ( currVersion < documentItem.Versions.Count - 1 )
                                doc.FileLength = documentItem.File.Versions [ currVersion ].Size;
                            else
                                doc.FileLength = documentVersion.ListItem.File.Length;
                            documentVersions.Add ( doc );
                            currVersion--;
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return documentVersions;
        }

        public Document Save ( Document document, Guid siteCollectionId, string serverRelativeUrl )
        {
            if ( document.IsFolder )
                document = SaveFolder ( document, siteCollectionId, serverRelativeUrl );
            else
                document = SaveFile ( document, siteCollectionId, serverRelativeUrl );

            return document;
        }

        private Document SaveFolder ( Document document, Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    web.AllowUnsafeUpdates = true;

                    SPList list = web.Lists [ Constants.SPListNames.Documents ];
                    SPFolder folder = document.EditType == EditType.Created ? web.GetFolder ( document.FolderUrl ) : web.GetFolder ( document.Url );
                    SPListItem listItem = null;

                    #region Created
                    if ( document.EditType == EditType.Created )
                    {
                        folder = folder.SubFolders.Add ( document.FolderUrl + "/" + document.Title );

                        listItem = folder.Item;
                        listItem [ DocumentFieldNames.ServerRelativeUrl ] = folder.ServerRelativeUrl;
                        listItem [ DocumentFieldNames.SiteCollectionId ] = siteCollectionId;
                        listItem [ DocumentFieldNames.Description ] = document.Description;

                        listItem.UpdateOverwriteVersion ( );

                        document = SPDataHelpers.MakeDocumentFromFolderItem ( listItem );
                    }
                    #endregion
                    #region Updated
                    else if ( document.EditType == EditType.Updated )
                    {
                        listItem = folder.Item;

                        string path = document.ServerRelativeUrl;
                        path = path.Substring ( 0, path.LastIndexOf ( "/" ) + 1 ) + document.Title;

                        listItem [ DocumentFieldNames.Description ] = document.Description;
                        listItem [ DocumentFieldNames.ServerRelativeUrl ] = path;
                        listItem.UpdateOverwriteVersion ( );

                        if ( folder.Exists && folder.ServerRelativeUrl != path )
                            folder.MoveTo ( path );
                    }
                    #endregion
                    #region Deleted
                    else if ( document.EditType == EditType.Deleted )
                    {
                        if ( folder.Exists )
                            folder.Item.Recycle ( );
                    }
                    #endregion

                    web.AllowUnsafeUpdates = false;
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return document;
        }

        private Document SaveFile ( Document document, Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    web.AllowUnsafeUpdates = true;

                    SPList list = web.Lists [ Constants.SPListNames.Documents ];
                    SPFolder folder = web.GetFolder ( document.FolderUrl ?? document.Url );
                    SPFile file = null;
                    SPListItem listItem = null;

                    #region Created
                    if ( document.EditType == EditType.Created )
                    {
                        if ( document.CreatedBy != null && document.ModifiedBy != null )
                        {
                            SPUser createdBy = web.AllUsers.GetByID ( document.CreatedBy.SPUserId );
                            SPUser modifiedBy = web.AllUsers.GetByID ( document.ModifiedBy.SPUserId );
                            file = folder.Files.Add ( document.Title, document.FileBytes, createdBy, modifiedBy, document.CreatedDate, document.ModifiedDate );
                            file.Item [ "Created" ] = document.CreatedDate;
                            file.Item [ "Modified" ] = document.ModifiedDate;
                        }
                        else
                            file = folder.Files.Add ( document.Title, document.FileBytes, true, "", false );

                        listItem = file.Item;
                        listItem [ DocumentFieldNames.ServerRelativeUrl ] = folder.ServerRelativeUrl;
                        listItem [ DocumentFieldNames.SiteCollectionId ] = siteCollectionId;
                        listItem [ DocumentFieldNames.CurrentVersion ] = file.MajorVersion;
                        listItem [ DocumentFieldNames.IsProjectPlan ] = document.IsProjectPlan;
                        listItem [ DocumentFieldNames.Description ] = document.Description;

                        listItem.UpdateOverwriteVersion ( );

                        document = SPDataHelpers.MakeDocumentFromFileItem ( listItem );
                        document.IsCreatedThisWeekAdd = true;
                    }
                    #endregion
                    #region Updated
                    else if ( document.EditType == EditType.Updated )
                    {
                        listItem = list.GetItemById ( document.Id );
                        if ( document.FileBytes != null && document.FileBytes.Length > 0 )
                        {
                            file = folder.Files.Add ( document.Title, document.FileBytes, true, "", false );
                        }
                        else
                        {
                            if ( listItem [ DocumentFieldNames.FileLeafRef ].ToString ( ) != document.Title )
                            {
                                listItem [ DocumentFieldNames.FileLeafRef ] = document.Title;
                                listItem.Update ( );
                            }
                            file = listItem.File;
                        }

                        listItem [ DocumentFieldNames.CurrentVersion ] = file.MajorVersion;
                        listItem [ DocumentFieldNames.IsProjectPlan ] = document.IsProjectPlan;
                        listItem [ DocumentFieldNames.Description ] = document.Description;

                        listItem.UpdateOverwriteVersion ( );
                    }
                    #endregion
                    #region Deleted
                    else if ( document.EditType == EditType.Deleted )
                    {
                        file = web.GetFile ( document.Url );
                        if ( file.Exists )
                            file.Item.Recycle ( );
                    }
                    #endregion

                    web.AllowUnsafeUpdates = false;
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return document;
        }

        public Document RestoreVersion ( Document document, string versionLabel, Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    SPList documentList = web.Lists [ Constants.SPListNames.Documents ];

                    SPListItem documentItem = documentList.GetItemById ( document.Id );

                    documentItem.File.Versions.RestoreByLabel ( versionLabel );

                    document = SPDataHelpers.MakeDocumentFromFileItem ( documentItem );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return document;
        }

        public void MoveDocument ( int itemId, string destination, Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    web.AllowUnsafeUpdates = true;

                    SPList list = web.Lists [ Constants.SPListNames.Documents ];
                    SPListItem item = list.GetItemById ( itemId );

                    if ( item.File != null && item.File.Exists )
                    {
                        string newUrl = string.Format ( "{0}/{1}", destination, item.File.Name );
                        item.File.MoveTo ( newUrl, false );
                    }
                    else if ( item.Folder != null && item.Folder.Exists )
                    {
                        string newUrl = string.Format ( "{0}/{1}", destination, item.Folder.Name );
                        item.Folder.MoveTo ( newUrl );
                    }

                    web.AllowUnsafeUpdates = false;
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }
        }

        public SPFolder GetAllFolders ( Guid siteCollectionId, string serverRelativeUrl )
        {
            SPFolder documents = null;

            try
            {
                using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    documents = web.Folders [ Constants.SPListNames.Documents ];
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return documents;
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.DataAccess/DocumentDA.cs $
 * 
 * 29    2/08/10 5:04p Camerons
 * 
 * 28    2/08/10 12:00p Camerons
 * 
 * 27    1/25/10 1:17p Camerons
 * 
 * 26    1/20/10 3:04p Camerons
 * 
 * 25    1/12/10 12:02p Camerons
 * 
 * 24    26/11/09 10:35a Camerons
 * 
 * 23    11/26/09 10:12a Stefanf
 * 
 * 22    17/11/09 6:46p Camerons
 * 
 * 21    9/11/09 9:00p Camerons
 * 
 * 20    9/11/09 1:23p Camerons
 * 
 * 19    9/11/09 1:18p Camerons
 * 
 * 18    8/11/09 3:00p Camerons
 * 
 * 17    28/10/09 11:18a Tobys
 * 
 * 16    28/10/09 1:30a Tobys
 * Finalized changes to support saving a document with a different author
 * than the current user.
 * 
 * 15    10/27/09 5:38p Adamw
 * cleanup and code to use IsProjectPlan property
 * 
 * 14    27/10/09 2:36p Tobys
 * 
 * 13    10/22/09 10:28a Adamw
 * Case 345, changed subfolders and subfiles to use the same EditType as
 * root document object, changed the rename of the folder to the
 * recommended approach of using folder.MoveTo instead of a field value
 * change (metadata is kept)
 * 
 * 12    21/09/09 3:30p Camerons
 * First batch of changes for 1.1.x.x - Security groups update
 * 
 * 11    17/08/09 10:41a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/